#include <d3d9.h>
#include <d3dx9.h>
#include <windows.h>
#include "Game.h"
#include "Trace.h"
#include <time.h>

/**--------------------------------------------------------
*Description : Constructor
*Method name : Game
*Parameters :  HINSTANCE hInstance, LPWSTR Name, int Mode, int IsFullScreen, int FrameRate
*Return value :
--------------------------------------------------------**/
Game::Game(HINSTANCE hInstance, LPWSTR Name, int Mode, int IsFullScreen, int FrameRate)
{
	d3d = new DirectX();


	/*_d3d = NULL;
	_d3ddv = NULL;
	_BackBuffer = NULL;*/

	/*_di = NULL;
	_Keyboard = NULL;*/

	_Mode = Mode;
	_SetScreenDimension(Mode);
	_Name = Name;
	_IsFullScreen = IsFullScreen;
	_FrameRate = FrameRate;

	_hInstance = hInstance;

	input = new DxInput();
	
	timer = new Timer();


	srand((unsigned)(time(NULL)));
}


/**--------------------------------------------------------
*Description : Thiet dat che do man hinh
*Method name : _SetScreenDimension
*Parameters :  int Mode
*Return value :void
--------------------------------------------------------**/
void Game::_SetScreenDimension(int Mode)
{
	switch (Mode)
	{
	case GL_GAME_SCREEN_RESOLUTION_640_480_24:
		_ScreenWidth = 640; 
		_ScreenHeight = 480;
		_Depth = 24;
		_BackBufferFormat = D3DFMT_X8R8G8B8;
		break;

	case GL_GAME_SCREEN_RESOLUTION_800_600_24:
		_ScreenWidth = 800; 
		_ScreenHeight = 600;
		_Depth = 24;
		_BackBufferFormat = D3DFMT_X8R8G8B8;
		break;

	case GL_GAME_SCREEN_RESOLUTION_1024_768_24:
		_ScreenWidth = 1024; 
		_ScreenHeight = 768;
		_Depth = 24;
		_BackBufferFormat = D3DFMT_X8R8G8B8;
		break;

	default: 
		break;
	}
}


/**--------------------------------------------------------
*Description : Khoi tao cua so man hinh
*Method name : _InitWindow
*Parameters :  
*Return value :void
--------------------------------------------------------**/
void Game::_InitWindow()
{
	MSG msg;
	WNDCLASSEX wc;
	//WNDCLASS wc;
	wc.cbSize = sizeof(WNDCLASSEX);
	ZeroMemory(&msg,sizeof(msg));
	wc.style = CS_HREDRAW | CS_VREDRAW;
	wc.hInstance = _hInstance;

	wc.lpfnWndProc = (WNDPROC)Game::_WinProc;
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hIcon = NULL;
	wc.hIcon = LoadIcon(NULL,IDI_APPLICATION);
	wc.hCursor = LoadCursor(NULL, IDC_ARROW);
	
	wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
	wc.lpszMenuName = NULL;
	wc.lpszClassName = _Name;
	wc.hIconSm = NULL;
	
	RegisterClassEx(&wc);
	//if(!RegisterClass(&wc)) return;

	DWORD style; 
	if (_IsFullScreen)
		style = WS_EX_TOPMOST | WS_VISIBLE | WS_POPUP;
	else 
		style = WS_OVERLAPPEDWINDOW;

	/*_hWnd = 
	CreateWindow(
	_Name,
	_Name,
	style, 
	CW_USEDEFAULT,
	CW_USEDEFAULT, 
	_ScreenWidth,
	_ScreenHeight,
	NULL,
	NULL,
	_hInstance,
	NULL);*/

	_hWnd = 
		CreateWindow(
		_Name,
		_Name,
		WS_OVERLAPPED,//style, 
		100,
		100, 
		_ScreenWidth,
		_ScreenHeight,
		NULL,
		NULL,
		_hInstance,
		this//NULL
		);
	
	if (!_hWnd) 
	{ 
		trace(L"[ERROR] Failed to created window!");
		DWORD ErrCode = GetLastError();
	}

	ShowWindow(_hWnd,SW_SHOWNORMAL);
	//ShowWindow(_hWnd,SW_SHOW);
	UpdateWindow(_hWnd);
}


/**--------------------------------------------------------
*Description : Khoi tao Direct3D
*Method name : _InitDirectX
*Parameters :  
*Return value :void
--------------------------------------------------------**/
void Game::_InitDirectX()
{
	/*_d3d = Direct3DCreate9(D3D_SDK_VERSION);
	D3DPRESENT_PARAMETERS d3dpp; 

	ZeroMemory( &d3dpp, sizeof(d3dpp) );

	d3dpp.Windowed = _IsFullScreen?FALSE:TRUE;

	d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;

	d3dpp.BackBufferFormat = _BackBufferFormat; 
	d3dpp.BackBufferCount = 1;
	d3dpp.BackBufferHeight = _ScreenHeight;
	d3dpp.BackBufferWidth = _ScreenWidth;

	_d3d->CreateDevice(
			D3DADAPTER_DEFAULT,
			D3DDEVTYPE_HAL,
			_hWnd,
			D3DCREATE_SOFTWARE_VERTEXPROCESSING,
			&d3dpp,
			&_d3ddv);

	if (_d3ddv==NULL) 
	{
		trace(L"[ERROR] Failed to created device!");
	}
	
	_d3ddv->GetBackBuffer(0,0,D3DBACKBUFFER_TYPE_MONO,&_BackBuffer);*/

	d3d->Init(_hWnd, _ScreenWidth, _ScreenHeight, _IsFullScreen);
}


/**--------------------------------------------------------
*Description : Khoi tao doi tuong ban phim
*Method name : _InitKeyboard
*Parameters :  
*Return value :void
--------------------------------------------------------**/
void Game::_InitKeyboard()
{
 //   HRESULT 
	//	hr = DirectInput8Create
	//		( 
	//			_hInstance, 
	//			DIRECTINPUT_VERSION, 
	//			IID_IDirectInput8, (VOID**)&_di, NULL 
	//		);

	//// TO-DO: put in exception handling
	//if (hr!=DI_OK) return;

	//trace(L"DirectInput has been created");

	//hr = _di->CreateDevice(GUID_SysKeyboard, &_Keyboard, NULL); 
	//
	//// TO-DO: put in exception handling
	//if (hr!=DI_OK) return;

	//trace(L"DirectInput keyboard has been created");

 //   // Set the data format to "keyboard format" - a predefined data format 
 //   //
 //   // A data format specifies which controls on a device we
 //   // are interested in, and how they should be reported.
 //   //
 //   // This tells DirectInput that we will be passing an array
 //   // of 256 bytes to IDirectInputDevice::GetDeviceState.

	//hr = _Keyboard->SetDataFormat(&c_dfDIKeyboard);

	//trace(L"SetDataFormat for keyboard successfully");

	//hr = _Keyboard->SetCooperativeLevel(_hWnd, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE); 

	//trace(L"SetCooperativeLevel for keyboard successfully");

 //   // IMPORTANT STEP TO USE BUFFERED DEVICE DATA!
 //   //
 //   // DirectInput uses unbuffered I/O (buffer size = 0) by default.
 //   // If you want to read buffered data, you need to set a nonzero
 //   // buffer size.
 //   //
 //   // Set the buffer size to DINPUT_BUFFERSIZE (defined above) elements.
 //   //
 //   // The buffer size is a DWORD property associated with the device.
 //   DIPROPDWORD dipdw;

 //   dipdw.diph.dwSize       = sizeof(DIPROPDWORD);
 //   dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
 //   dipdw.diph.dwObj        = 0;
 //   dipdw.diph.dwHow        = DIPH_DEVICE;
 //   dipdw.dwData            = GL_KEYBOARD_BUFFER_SIZE; // Arbitary buffer size

	//trace(L"SetProperty for keyboard successfully");

 //   hr = _Keyboard->SetProperty( DIPROP_BUFFERSIZE, &dipdw.diph );
	//if (hr!=DI_OK) return;

	//hr = _Keyboard->Acquire(); 
	//if (hr!=DI_OK) return;

	//trace(L"Keyboard has been acquired successfully");


	/*_InitDirectInput(_hWnd);
	_Init_Keyboard(_hWnd);*/

	input->_InitDirectInput(_hInstance, _hWnd);
	//input->_Init_Keyboard(_hWnd);
	//input->_InitMouse(_hWnd, _ScreenWidth/2, _ScreenHeight/2);
}


/**--------------------------------------------------------
*Description : Khoi tao Game
*Method name : Init
*Parameters :  
*Return value :void
--------------------------------------------------------**/
void Game::Init()
{
	_InitWindow();
	_InitDirectX();
	_InitKeyboard();
	//LoadResources(_d3ddv);

	//initialize DirectSound
	//if (!Init_DirectSound(_hWnd))
	//{
	//	MessageBox(_hWnd, L"Error initializing DirectSound", L"Error", MB_OK);
	//	//return 0;
	//}

	LoadResources(d3d->GetDevice(), d3d->GetBackBuffer());
}


/**--------------------------------------------------------
*Description : Lay trang thai cua ban phim
*Method name : _ProcessKeyBoard
*Parameters :  
*Return value :void
--------------------------------------------------------**/
void Game::_ProcessKeyBoard()
{
		// Collect all key states first
		//_Keyboard->GetDeviceState( sizeof(_KeyStates), _KeyStates);

		/*if (IsKeyDown(DIK_ESCAPE)) 
		{
			trace(L"Escape key pressed!");
			PostMessage(_hWnd,WM_QUIT,0,0);
		}*/

		/*if (input->IsKeyDown(DIK_ESCAPE)) 
		{
			trace(L"Escape key pressed!");
			PostMessage(_hWnd,WM_QUIT,0,0);
		}*/

		// Collect all buffered events
		//DWORD dwElements = GL_KEYBOARD_BUFFER_SIZE;
		//HRESULT hr = _Keyboard->GetDeviceData( sizeof(DIDEVICEOBJECTDATA), _KeyEvents, &dwElements, 0 );

		//// Scan through all data, check if the key is pressed or released
		//for( DWORD i = 0; i < dwElements; i++ ) 
		//{
		//	int KeyCode = _KeyEvents[i].dwOfs;
		//	int KeyState = _KeyEvents[i].dwData;
		//	if ( (KeyState & 0x80) > 0)
		//		OnKeyDown(KeyCode);
		//	else 
		//		OnKeyUp(KeyCode);
		//}
		//_Process_KeyBoard();

		input->_Process_KeyBoard();
		input->_GetMouse();
}


/**--------------------------------------------------------
*Description : Run Game
*Method name : Run
*Parameters :  
*Return value :void
--------------------------------------------------------**/
void Game::Run()
{
	MSG msg;
	int done = 0;
	DWORD frame_start = GetTickCount();
	
	DWORD tick_per_frame = 100 / _FrameRate;
	
	trace(L">>> Main game loop has been started");

	while (!done) 
	{
		if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
		{
			if (msg.message==WM_QUIT) done=1;

			TranslateMessage(&msg);
			DispatchMessage(&msg);			
		}

		//DWORD now = GetTickCount();
		//_DeltaTime = now - frame_start; 
		//if (_DeltaTime >= tick_per_frame)
		//{
		//	frame_start = now;
		//	//_UpdateGame();
		//	_RenderFrame();
		//	
		//}
		////_RenderFrame();
		//_ProcessKeyBoard();
		//

		////ProcessInput(_d3ddv, _DeltaTime);
		//ProcessInput(d3d->GetDevice(), _DeltaTime);


		timer->LimitFPS(60);
		TPF = timer->TPF;
		_DeltaTime = TPF*1000;
		_RenderFrame();
		_ProcessKeyBoard();
		ProcessInput(d3d->GetDevice(), _DeltaTime);
	}
	
	/*if (this != NULL)
	{
		delete this;
		 
	}*/
	
	trace(L"Main game loop has ended");
}


/**--------------------------------------------------------
*Description : Render Frame
*Method name : _RenderFrame
*Parameters :  
*Return value :void
--------------------------------------------------------**/
void Game::_RenderFrame()
{
	
	/*if (_d3ddv->BeginScene()) 
	{
		RenderFrame(_d3ddv, _DeltaTime);
		_d3ddv->EndScene();
	}
	_d3ddv->Present(NULL,NULL,NULL,NULL);*/
	if (d3d->GetDevice()->BeginScene()) 
	{
		////Moi them Update
		Update(d3d->GetDevice(), d3d->GetBackBuffer(), _DeltaTime);

		RenderFrame(d3d->GetDevice(), d3d->GetBackBuffer(), _DeltaTime);
		d3d->GetDevice()->EndScene();
	}
	d3d->GetDevice()->Present(NULL,NULL,NULL,NULL);
}


/**--------------------------------------------------------
*Description : Render Frame
*Method name : RenderFrame
*Parameters :  
*Return value :void
--------------------------------------------------------**/
void Game::RenderFrame(LPDIRECT3DDEVICE9 d3ddv, LPDIRECT3DSURFACE9 BackBuffer, int Delta) 
{
	//d3ddv->ColorFill(_BackBuffer,NULL,D3DCOLOR_XRGB(0,0,0));
	d3ddv->ColorFill(BackBuffer,NULL,D3DCOLOR_XRGB(0,0,0));
}


/**--------------------------------------------------------
*Description : Load Resources
*Method name : LoadResources
*Parameters :  LPDIRECT3DDEVICE9 d3ddv
*Return value :void
--------------------------------------------------------**/
void Game::LoadResources(LPDIRECT3DDEVICE9 d3ddv, LPDIRECT3DSURFACE9 BackBuffer) { }


/**--------------------------------------------------------
*Description : Process Input
*Method name : ProcessInput
*Parameters :  LPDIRECT3DDEVICE9 d3ddv, int Delta
*Return value :void
--------------------------------------------------------**/
void Game::ProcessInput(LPDIRECT3DDEVICE9 d3ddv, int Delta) { }


/**--------------------------------------------------------
*Description : Huy game
*Method name : ~Game
*Parameters :   
*Return value :
--------------------------------------------------------**/
Game::~Game()
{
	/*if (_d3ddv!=NULL) _d3ddv->Release();
	if (_d3d!=NULL) _d3d->Release();*/

	d3d->Shutdown();
    /*if( _Keyboard )  
	{
		_Keyboard->Unacquire();
		_Keyboard->Release();
	}

    if (_di) _di->Release();*/
	//_KillKeyboard();
	//input->_KillMouse();
	input->_KillDirectInput();
}




/**--------------------------------------------------------
*Description : Nhan tin nhan tu he thong
*Method name : _WinProc
*Parameters :  HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam 
*Return value :void
--------------------------------------------------------**/
LRESULT CALLBACK Game::_WinProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	switch (message) 
	{
	case WM_DESTROY:
		 
		PostQuitMessage(0);
		break;
	default: 
		return DefWindowProc(hWnd, message, wParam,lParam);
	}

	return 0;
	/*switch (message) 
	{
	case WM_DESTROY: 
		PostQuitMessage(0);
		break;
	
		
	}

	return DefWindowProc(hWnd, message, wParam,lParam);*/
}

void Game::Update(LPDIRECT3DDEVICE9 d3ddv, LPDIRECT3DSURFACE9 Backbuffer, int Delta){}

void Game::_UpdateGame()
{
	//Moi them Update
	//Update(d3d->GetDevice(), d3d->GetBackBuffer(), _DeltaTime);
}